package com.yunban.project.api.text_check.service.impl;

import com.alibaba.fastjson2.JSON;
import com.yunban.project.api.text_check.domain.CorrectionConfig;
import com.yunban.project.api.text_check.service.AiCorrectionService;
import com.yunban.project.api.text_check.service.CorrectionService;
import jakarta.annotation.Resource;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.base.common.exception.BusinessException;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.List;

/**
 * @author: lijiajun
 * @date: 2025-01-06
 * @version: 1.0
 */
@Slf4j
@Service("jiaoDuiCorrectionService")
public class IJiaoDuiCorrectionServiceImpl implements CorrectionService {

    @Resource
    private RestTemplate restTemplate;

    private static final String TOKEN_URL = "https://www.ijiaodui.com:8080/component/v1/api_token";

    private String getAccessToken(String appId, String appSecret) {
        // post请求，调用TOKEN_URL获取token
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HashMap<String, String> params = new HashMap<>();
        params.put("app_id", appId);
        params.put("app_secret", appSecret);
        HttpEntity<Object> objectHttpEntity = new HttpEntity<>(JSON.toJSONString(params), headers);
        try {
            ResponseEntity<AccessTokenResp> responseEntity = this.restTemplate.postForEntity(TOKEN_URL, objectHttpEntity, AccessTokenResp.class);
            if (!responseEntity.getStatusCode().is2xxSuccessful()) {
                log.error("【IJiaoDuiCorrectionServiceImpl】getAccessToken 获取失败：{}", responseEntity.getStatusCode());
                return null;
            }
            AccessTokenResp accessTokenResp = responseEntity.getBody();
            if (ObjectUtils.isEmpty(accessTokenResp)) {
                return null;
            }
            // 判断是否抛出了异常
            if (StringUtils.hasText(accessTokenResp.getMsg())) {
                throw new BusinessException(accessTokenResp.getMsg());
            }
            log.info("【IJiaoDuiCorrectionServiceImpl】getAccessToken result:{}", JSON.toJSONString(accessTokenResp));
            return accessTokenResp.getAccess_token();
        } catch (Exception ex) {
            log.error("【IJiaoDuiCorrectionServiceImpl】getAccessToken 获取失败：{}", ex.getMessage());
            return null;
        }
    }

    @Override
    public String correction(String text, CorrectionConfig config, String taskId) {
        String appId = config.getApiKey();
        String appSecret = config.getApiSecret();
        String accessToken = this.getAccessToken(appId, appSecret);
        if (!StringUtils.hasText(accessToken)) {
            return null;
        }
        // 将token拼接到url中
        String urlPath = config.getUrlPath() + "?access_token=" + accessToken;
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HashMap<String, String> params = new HashMap<>();
        params.put("text", text);
        HttpEntity<Object> objectHttpEntity = new HttpEntity<>(JSON.toJSONString(params), headers);
        try {
            log.info("【IJiaoDuiCorrectionServiceImpl】correction url:{}", urlPath);
            ResponseEntity<CorrectResp> responseEntity = this.restTemplate.postForEntity(urlPath, objectHttpEntity, CorrectResp.class);
            if (!responseEntity.getStatusCode().is2xxSuccessful()) {
                log.error("【IJiaoDuiCorrectionServiceImpl】correction 获取结果失败：{}", responseEntity.getStatusCode());
                return null;
            }
            CorrectResp correctResp = responseEntity.getBody();
            if (ObjectUtils.isEmpty(correctResp)) {
                return null;
            }
            // 判断返回值是否存在
            if (ObjectUtils.isEmpty(correctResp.getResult())) {
                log.warn("【IJiaoDuiCorrectionServiceImpl】correction 获取结果失败：{}", correctResp.getMsg());
                return null;
            }
            return parseCorrectResult(text, correctResp);
        } catch (Exception ex) {
            log.error("【IJiaoDuiCorrectionServiceImpl】correction 获取失败：{}", ex.getMessage());
            return null;
        }
    }

    public String parseCorrectResult(String text, CorrectResp correctResp) {
        List<CorrectPosition> mistakes = correctResp.getResult().getMistakes();
        // 使用 StringBuilder 来构建新的句子
        StringBuilder correctedText = new StringBuilder(text);
        // 按照位置从大到小排序，避免替换时影响后续位置
        List<IJiaoDuiCorrectionServiceImpl.CorrectPosition> sortedMistakes = mistakes.stream().sorted((r1, r2) -> Integer.compare(r2.getL(), r1.getL())).toList();
        // 将api返回的结构转为一段已经更改的文本
        for (IJiaoDuiCorrectionServiceImpl.CorrectPosition mistake : sortedMistakes) {
            int l = mistake.getL();
            int r = mistake.getR();
            if (!mistake.getInfos().isEmpty()) {
                // 获取推荐的修正内容，默认选择第一个推荐信息
                String recommend = mistake.getInfos().get(0).getRecommend();
                // 替换指定范围内的文本
                correctedText.replace(l, r, recommend);
            }
        }
        return correctedText.toString();
    }

    @Data
    public static class MessageResp {
        private int code;
        private String msg;
    }

    @Data
    @EqualsAndHashCode(callSuper = true)
    public static class AccessTokenResp extends MessageResp {
        private String access_token;
        private int expires_in;
    }

    @Data
    @EqualsAndHashCode(callSuper = true)
    public static class CorrectResp extends MessageResp {
        private CorrectResult result;
        private int sum;
    }

    @Data
    public static class CorrectResult {
        private String sentence;
        private int mistake_num;
        private List<CorrectPosition> mistakes;
    }

    // 纠错位置
    @Data
    public static class CorrectPosition {
        private int l;
        private int r;
        private List<CorrectInfo> infos;
    }

    @Data
    public static class CorrectInfo {
        private String recommend;
        private int type;
        private String category;
    }
}
